package com.huabo.sql.mapper;

import com.huabo.sql.builder.SelectBuilder;
import com.huabo.sql.record.DomainModelContext;
import com.huabo.sql.record.DomainModelAnalysis;
import com.huabo.sql.record.TableColumn;
import com.huabo.sql.type.JdbcType;
import com.huabo.sql.type.TypeHandler;
import com.huabo.sql.type.TypeHandlerRegistry;
import com.huabo.utils.SpringContextHelper;
import org.springframework.beans.BeanUtils;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.util.ReflectionUtils;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

/**
 * 默认的ORM方式
 *
 * @param <T>
 * @author Jackie Liu
 */
public class DefaultRowMapper<T> implements RowMapper<T> {

    private DomainModelAnalysis domainModelAnalysis;

    public DefaultRowMapper(DomainModelAnalysis domainModelAnalysis) {
        this.domainModelAnalysis = domainModelAnalysis;
    }

    public DefaultRowMapper(Class<T> cls) {
        DomainModelContext commonModelContext = SpringContextHelper.getBean(DomainModelContext.class);
        domainModelAnalysis = commonModelContext.getDomainModelAnalysis(cls);
    }

    @SuppressWarnings({"unchecked", "rawtypes"})
    @Override
    public T mapRow(ResultSet rs, int rowNum) throws SQLException {
        ResultSetMetaData metaData = rs.getMetaData();
        int count = metaData.getColumnCount();
        T t = (T) BeanUtils.instantiate(domainModelAnalysis.getClazz());
        TypeHandlerRegistry typeHandlerRegistry = DomainModelContext.getTypeHandlerRegistry();
        for (int i = 1; i <= count; i++) {
            String colName = metaData.getColumnLabel(i).toUpperCase();
            TableColumn tableColumn = domainModelAnalysis.getTableColumn(colName);
            if (tableColumn == null) {
                extendColumnRow(colName, t, metaData, i, rs, typeHandlerRegistry);
                continue;
            }

            TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(tableColumn.getJavaType());
            if (typeHandler == null) {
                int columnType = metaData.getColumnType(i);
                typeHandler = typeHandlerRegistry.getTypeHandler(JdbcType.forCode(columnType));
            }
            //System.out.println(colName + " ; " + typeHandler);
            ReflectionUtils.invokeMethod(tableColumn.getFieldSetMethod(), t, typeHandler.getResult(rs, i));
        }
        return t;
    }

    private boolean extendColumnRow(String colName, T t, ResultSetMetaData metaData, int index, ResultSet rs, TypeHandlerRegistry typeHandlerRegistry) throws SQLException {
        SelectBuilder.Column column = SelectBuilder.getExtendColumn(colName);
        if (column == null) {
            return false;
        }
        Object manyToOne = ReflectionUtils.invokeMethod(column.getGetModelMethod(), t);
        if (manyToOne == null) {
            manyToOne = BeanUtils.instantiate(column.getManyToOneClass());
            ReflectionUtils.invokeMethod(column.getSetModelMethod(), t, manyToOne);
        }

        TableColumn tableColumn = column.getManyToOneTableColumn();
        int columnType = metaData.getColumnType(index);
        TypeHandler typeHandler = typeHandlerRegistry.getTypeHandler(JdbcType.forCode(columnType));
        if (typeHandler == null) {
            typeHandler = typeHandlerRegistry.getTypeHandler(tableColumn.getJavaType());
        }
        ReflectionUtils.invokeMethod(tableColumn.getFieldSetMethod(), manyToOne, typeHandler.getResult(rs, index));
        return true;
    }
}